﻿using System;
using System.Collections.Generic;

namespace StockLib
{
    public partial class StockIndicator
    {
        protected List<Dictionary<int, float>> cacheValues = new List<Dictionary<int, float>>();

        public float valueMin { get; protected set; }
        public float valueMax { get; protected set; }
        public virtual int indexStart { get; set; }
        public virtual int indexEnd { get; set; }
        public virtual List<KData> kData { get; set; }

        public StockIndicator()
        {
            SetDefaultParameters();
        }

        protected int cacheCount
        {
            get
            {
                return cacheValues.Count;
            }
            set
            {
                cacheValues.Clear();
                for (int i = 0; i < value; i++)
                {
                    cacheValues.Add(new Dictionary<int, float>());
                }
            }
        }

        public virtual void SetDefaultParameters()
        {
        }

        public virtual void AttachParameters(StockIndicator src)
        {
        }

        public virtual bool IsValidParameters()
        {
            return true;
        }

        public virtual void Clear()
        {
            for (int i = 0; i < cacheValues.Count; i++)
            {
                cacheValues[i].Clear();
            }
        }

        public virtual void CalcMinMax()
        {
            valueMin = Int32.MaxValue;
            valueMax = Int32.MinValue;
            for (int i = indexStart; i <= indexEnd; i++)
            {
                float[] indicatorValues = CalcOutput(i);
                if (indicatorValues != null)
                {
                    foreach (float indicator in indicatorValues)
                    {
                        if (indicator > valueMax)
                            valueMax = indicator;
                        if (indicator > Int32.MinValue && indicator < valueMin)
                            valueMin = indicator;
                    }
                }
            }
        }

        protected virtual float[] CalcOutput(int index)
        {
            return null;
        }

        protected float CalcCloseMa(int index, int days)
        {
            if (index < days)
                return Int32.MinValue;

            float sum = 0;
            for (int i = index - days + 1; i <= index; i++)
            {
                sum += kData[i].Close;
            }
            return sum / days;
        }

        protected float CalcCloseMaCache(int index, int days, int cacheIndex)
        {
            if (cacheIndex < 0 || cacheIndex >= cacheCount)
                throw new IndexOutOfRangeException("缓冲索引超出范围");

            if (!cacheValues[cacheIndex].ContainsKey(index))
            {
                cacheValues[cacheIndex].Add(index, CalcCloseMa(index, days));
            }

            return cacheValues[cacheIndex][index];
        }

        protected float CalcVolumeMa(int index, int days)
        {
            if (index < days)
                return Int32.MinValue;

            float sum = 0;
            for (int i = index - days + 1; i <= index; i++)
            {
                sum += kData[i].Volume;
            }
            return sum / days;
        }

        protected float CalcVolumeMaCache(int index, int days, int cacheIndex)
        {
            if (cacheIndex < 0 || cacheIndex >= cacheCount)
                throw new IndexOutOfRangeException("缓冲索引超出范围");

            if (!cacheValues[cacheIndex].ContainsKey(index))
            {
                cacheValues[cacheIndex].Add(index, CalcVolumeMa(index, days));
            }

            return cacheValues[cacheIndex][index];
        }

        protected float CalcAmountMa(int index, int days)
        {
            if (index < days)
                return Int32.MinValue;

            float sum = 0;
            for (int i = index - days + 1; i <= index; i++)
            {
                sum += kData[i].Amount;
            }
            return sum / days;
        }

        protected float CalcAmountMaCache(int index, int days, int cacheIndex)
        {
            if (cacheIndex < 0 || cacheIndex >= cacheCount)
                throw new IndexOutOfRangeException("缓冲索引超出范围");

            if (!cacheValues[cacheIndex].ContainsKey(index))
            {
                cacheValues[cacheIndex].Add(index, CalcAmountMa(index, days));
            }

            return cacheValues[cacheIndex][index];
        }
    }
}
